/********************************************************************
* プロジェクト名: 27MUART_R
* PIC24F64GB002 + SDカード


********************************************************************/
#include <p24fj64gb002.h>
#include "USB/USB.h"
#include "HardwareProfile.h"
#include "USB/usb_function_cdc.h"
#include "MDD File System/SD-SPI.h"
#include "MDD File System/FSIO.h"
#include "USB/usb_function_msd.h"



_CONFIG1(WINDIS_OFF & FWDTEN_OFF & ICS_PGx1 & GCP_OFF & JTAGEN_OFF & GWRP_OFF)
_CONFIG2(POSCMOD_HS & I2C1SEL_PRI & OSCIOFNC_OFF & FCKSM_CSDCMD
& FNOSC_PRIPLL & PLL96MHZ_ON & PLLDIV_DIV2 & IESO_OFF)
_CONFIG3(SOSCSEL_IO)

#pragma udata
/* USB MSDクラス用関数呼び出しポインタ */
LUN_FUNCTIONS LUN[MAX_LUN + 1] =
{
{
&MDD_SDSPI_MediaInitialize, // メディア初期化
&MDD_SDSPI_ReadCapacity, // 容量読み出し
&MDD_SDSPI_ReadSectorSize, // セクタサイズ読み出し
&MDD_SDSPI_MediaDetect, // メディア検出
&MDD_SDSPI_SectorRead, // 1セクタ読み出し
&MDD_SDSPI_WriteProtectState, // 保護状態読み出し
&MDD_SDSPI_SectorWrite // セクタ書き込み
}
};
FSFILE *logFile;
BOOL initResults;
/* USB MSDクラスのSCSI INQUIRYコマンド応答用データ */
const ROM InquiryResponse inq_resp = {
0x00, // peripheral device is connected, direct access block device
0x80, // RMB removable
0x04, // ISO version=0, ECMA version=0, ANSI version=4=SPC-2
0x02, // response is in format specified by SPC-2
0x20, // Additional Length(n-4) = 36-4=32= 0x20
0x00, // sccs etc.
0x00, // etc
0x00, //bque=1 and cmdque=0,indicates simple queueing 00 is obsolete,
// but as in case of other device, we are just using 00
// 00 obsolete, 0x80 for basic task queueing
{'T','o','y','o','s','h','m','a'}, // T10 Vendor ID 8cha
{'C','A','R','D',' ','R','E','A','D','E','R',' ',' ',' ',' ',' '},//product ID 16cha
{'0','0','0','1'} // product revison 4cha
};



extern unsigned char SPIBuf[];
char SavBuf[256]; // 受信用バッファ
#define Max 256 // バッファサイズ

char Buf1[Max];


int Size1;


int Ptr, Size, Index, SendFlag, SendState;
char Flag, DFlag, temp, LogCnt;
unsigned long LogAdr;
char USBOutBuf[64];


const unsigned char StrMsg[] = "Start GPS Logger";
const unsigned char USBMsg[] = "Connect to USB! ";
const unsigned char TXSMsg[] = "Start USB Send! ";
const unsigned char TXEMsg[] = "Stop USB Send! ";


static void InitializeSystem(void);
void USBDeviceTasks(void);
void USBCBSendResume(void);


char Receive(void);
void Send(char Data);

void Logging(void);
void USBSend(void);

#pragma code




int main(void){

InitializeSystem(); // システム初期化

Ptr = 0;
DFlag = 0; // 表示モードフラグ
Size1 = 0; // センテンス受信カウンタリセット

logFile = NULL; // ログファイル未オープンにリセット

initResults = FSInit(); // ファイルシステム初期化
USBDeviceInit(); // USBデバイス初期化
USBDeviceAttach(); // USBデバイスアタッチ許可

PORTBbits.RB7 = 0;
PORTAbits.RA4 = 0;


while(1){



/********** USB接続中の場合 *************/
if((USBDeviceState >= CONFIGURED_STATE)&&(USBSuspendControl!=1)){
MSDTasks(); // ファイルシステムステート更新

delay_us(300); // MSDでパソコン開くため追加!

PORTBbits.RB7 = 0;
/*** USB CDCコマンド受信 ***/
if(getsUSBUSART(USBOutBuf,64) > 0){ // データ受信ポール
switch(USBOutBuf[0]){ // 最初の1文字チェック
case 's': // 送信開始

SendFlag = 1; // 送信中フラグオン
SendState = 1;
break;
case 'e': // 送信終了

SendFlag = 0; // 送信中フラグオフ
break;
}
}
/**** USB CDCデータ送信実行ステート *******/
if(SendFlag ==1) // 全センテンス受信完了待ち
USBSend(); // 全センテンスをステートで送信
}

/********** USB接続なしの場合 ***********/

else{
PORTBbits.RB7 = 0;

if(sw1){ // ログSW押すと


switch(PORTAbits.RA4){
case 0: PORTAbits.RA4 = 1; break; // LED(緑)の切替
case 1: PORTAbits.RA4 = 0; break;
default: break;
}

if(logFile != NULL){ // ログファイルが開かれているならば
FSfclose(logFile); // ファイルクローズ
logFile = NULL; // ログ中フラグリセット
LUNSoftAttach(0); // CPUから直ぐアタッチ確認
}
else{

LUNSoftDetach(0); // CPUアクセス禁止
logFile = FSfopen("CARDLog.csv",APPEND);
}
while(sw1);
delay_ms(50);
}

if(Size1 != 0){ // エンターで切った1センテンスずつ書き込み

if(logFile != NULL){
Logging();
}
Size1 = 0;

}

else
delay_ms(10);
}
}
return 0;
}


static void InitializeSystem(void){

CLKDIV = 0x0020; // 96MHz PLL On, CPU32MHz
AD1PCFG = 0xFFFF; // すべてデジタルに設定

TRISA = 0x000C;
TRISB = 0x8F67; // = 0x1000111101100111 RB2 RX、RB3 TX、
// RB5 /SW1、 RB7 LED(赤)、 RB13 CMD、RB14 CLK、RB15 D0

/* SPIピン割付 */
RPINR20bits.SDI1R = 15; // SDI1 -> RP15
RPOR6bits.RP13R = 7; // SDO1 -> RP13
RPOR7bits.RP14R = 8; // SCK1OUT -> RP14


/// UART1ピン割付
RPINR18bits.U1RXR = 2; // UART1 RX to RP2
RPOR1bits.RP3R = 3; // UART1 TX to RP3

/// UART1初期設定 4800bps 8ビット パリティなし、フロー制御なし
U1BRG = 207; // 4800bps@16MHz
U1MODE = 0b1000100000000000; //
U1STA = 0b0000010000000000; //
IFS0bits.U1RXIF = 0; // 受信割り込みフラグクリア
IEC0bits.U1RXIE =1; // 受信割り込み許可

}



// 受信割り込みで 1バイトずつセンテンス・バッファに入れる:

void __attribute__((interrupt, no_auto_psv)) _U1RXInterrupt(void){

char data;
PORTBbits.RB7 = 0;

IFS0bits.U1RXIF = 0; // 割り込みフラグクリア
if(U1STAbits.OERR|| U1STAbits.FERR) { // エラー

Ptr = 0; // バッファポインタリセット
U1STA &= 0xFFF0; // エラーフラグクリア
U1MODE = 0; // UART Disable
U1MODE = 0b1000100000000000; // UART1初期設定
U1STA = 0b0000010000000000; // UART1初期設定
IEC0bits.U1RXIE =1; // 受信割り込み許可
}
else {
data = U1RXREG; // 受信データ取得
if(Ptr < 250)
SavBuf[Ptr++] = data; // 格納
else{
Ptr = 0;
}


if(data == 0x0A){ // センテンス終了(0x0A = ”エンター”)ならば
Size = Ptr; // 受信バイト数保存
Ptr = 0; // ポインタリセット

memcpy(Buf1, SavBuf, Size); // バッファ1へコピー
Size1 = Size; // 受信バイト数保存
}
}
}



void USBSend(void){
switch(SendState){
case 1:
if(USBUSARTIsTxTrfReady()){
if(Size1 != 0)
putUSBUSART(Buf1, Size1);
SendState++;
}
break;

case 2:
if(USBUSARTIsTxTrfReady()){
Size1 = 0;

SendState = 1;
}
break;
default:
break;
}
CDCTxService();
}




void Logging(void){

if(Size1 != 0){
PORTBbits.RB7 = 1; // LED(赤) ON
FSfwrite((const void*)&Buf1[0], 1, Size1, logFile);
}
PORTBbits.RB7 = 0;
}



/***********************************************************
* ボーレート変更関数
*
*  条件: USB_CDC_SET_LINE_CODING_HANDLER が定義されていること
************************************************************/
#if defined(USB_CDC_SET_LINE_CODING_HANDLER)
void mySetLineCodingHandler(void)
{
//If the request is not in a valid range
if(cdc_notice.GetLineCoding.dwDTERate.Val > 115200)
{ // 115kbps以上なら何もしない
}
else{
// CDCドライバのボーレート変更
CDCSetBaudRate(cdc_notice.GetLineCoding.dwDTERate.Val);
}
}
#endif

// ***************************************************************************************
// ************** USB Callback Functions *************************************************
// ***************************************************************************************

/*******************************************************************
* Function: void USBCBSuspend(void)
*******************************************************************/
void USBCBSuspend(void)
{
#if 0
U1EIR = 0xFFFF;
U1IR = 0xFFFF;
U1OTGIR = 0xFFFF;
IFS5bits.USB1IF = 0;
IEC5bits.USB1IE = 1;
U1OTGIEbits.ACTVIE = 1;
U1OTGIRbits.ACTVIF = 1;
Sleep();
#endif
}
/*******************************************************************
* Function: void USBCBWakeFromSuspend(void)
*******************************************************************/
void USBCBWakeFromSuspend(void)
{
}
/********************************************************************
Function: void USBCB_SOF_Handler(void)
*******************************************************************/
void USBCB_SOF_Handler(void)
{
}
/*******************************************************************
* Function: void USBCBErrorHandler(void)
*******************************************************************/
void USBCBErrorHandler(void)
{
}
/*******************************************************************
* Function: void USBCBCheckOtherReq(void)
*******************************************************************/
void USBCBCheckOtherReq(void)
{
USBCheckMSDRequest();
}//end
/*******************************************************************
* Function: void USBCBStdSetDscHandler(void)
*******************************************************************/
void USBCBStdSetDscHandler(void)
{
}//end
/*******************************************************************
* Function: void USBCBInitEP(void)
*******************************************************************/
void USBCBInitEP(void)
{
#if (MSD_DATA_IN_EP == MSD_DATA_OUT_EP)
USBEnableEndpoint(MSD_DATA_IN_EP,USB_IN_ENABLED|USB_OUT_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP);
#else
USBEnableEndpoint(MSD_DATA_IN_EP,USB_IN_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP);
USBEnableEndpoint(MSD_DATA_OUT_EP,USB_OUT_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP);
#endif

USBMSDInit(); // ファイルシステム初期化
CDCInitEP(); // CDCクラス用エンドポイント初期化
}
/*******************************************************************
* Function: void USBCBSendResume(void)
*******************************************************************/
void USBCBSendResume(void)
{
static WORD delay_count;

if(USBGetRemoteWakeupStatus() == TRUE) {
//Verify that the USB bus is in fact suspended, before we send
//remote wakeup signalling.
if(USBIsBusSuspended() == TRUE) {
USBMaskInterrupts();
//Clock switch to settings consistent with normal USB operation.
USBCBWakeFromSuspend();
USBSuspendControl = 0;
USBBusIsSuspended = FALSE; //So we don't execute this code again,
//until a new suspend condition is detected.
delay_count = 3600U;
do {
delay_count--;
}while(delay_count);
//Now drive the resume K-state signalling onto the USB bus.
USBResumeControl = 1; // Start RESUME signaling
delay_count = 1800U; // Set RESUME line for 1-13 ms
do {
delay_count--;
}while(delay_count);
USBResumeControl = 0; //Finished driving resume signalling
USBUnmaskInterrupts();
}
}
}
/*******************************************************************
* Function: BOOL USER_USB_CALLBACK_EVENT_HANDLER
* (USB_EVENT event, void *pdata, WORD size)
*******************************************************************/
BOOL USER_USB_CALLBACK_EVENT_HANDLER(USB_EVENT event, void *pdata, WORD size)
{
switch(event)
{
case EVENT_TRANSFER:
lcd_cmd(0xC0);
break;
case EVENT_SOF:
USBCB_SOF_Handler();
break;
case EVENT_SUSPEND:
USBCBSuspend();
break;
case EVENT_RESUME:
USBCBWakeFromSuspend();
break;
case EVENT_CONFIGURED:
USBCBInitEP();
break;
case EVENT_SET_DESCRIPTOR:
USBCBStdSetDscHandler();
break;
case EVENT_EP0_REQUEST:
USBCBCheckOtherReq();
lcd_clear(); // USB接続メッセージ
lcd_str(USBMsg); // LCDに表示
break;
case EVENT_BUS_ERROR:
USBCBErrorHandler();
break;
case EVENT_TRANSFER_TERMINATED:

break;
default:
break;
}
return TRUE;
}